package com.xuecheng.orders.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xuecheng.base.exception.XueChengPlusException;
import com.xuecheng.base.utils.IdWorkerUtils;
import com.xuecheng.base.utils.QRCodeUtil;
import com.xuecheng.messagesdk.model.po.MqMessage;
import com.xuecheng.messagesdk.service.MqMessageService;
import com.xuecheng.orders.config.AlipayConfig;
import com.xuecheng.orders.config.PayNotifyConfig;
import com.xuecheng.orders.mapper.XcOrdersGoodsMapper;
import com.xuecheng.orders.mapper.XcOrdersMapper;
import com.xuecheng.orders.mapper.XcPayRecordMapper;
import com.xuecheng.orders.model.dto.AddOrderDto;
import com.xuecheng.orders.model.dto.PayRecordDto;
import com.xuecheng.orders.model.dto.PayStatusDto;
import com.xuecheng.orders.model.po.XcOrders;
import com.xuecheng.orders.model.po.XcOrdersGoods;
import com.xuecheng.orders.model.po.XcPayRecord;
import com.xuecheng.orders.service.OrderService;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageBuilder;
import org.springframework.amqp.core.MessageBuilderSupport;
import org.springframework.amqp.core.MessageDeliveryMode;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.ResponseBody;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
public class OrderServiceImpl implements OrderService {
    @Autowired
    XcOrdersMapper ordersMapper;
    @Autowired
    XcOrdersGoodsMapper ordersGoodsMapper;
    
    @Autowired
    XcPayRecordMapper payRecordMapper;

    @Autowired
    OrderService currentProxy;

    @Value("${pay.qrcodeurl}")
    String qrcodeurl;

    @Value("${pay.alipay.APP_ID}")
    String APP_ID;
    @Value("${pay.alipay.APP_PRIVATE_KEY}")
    String APP_PRIVATE_KEY;

    @Value("${pay.alipay.ALIPAY_PUBLIC_KEY}")
    String ALIPAY_PUBLIC_KEY;


    @Autowired
    RabbitTemplate rabbitTemplate;


    @Autowired
    MqMessageService mqMessageService;

    @Transactional
    @Override
    public PayRecordDto createOrder(String userId, AddOrderDto addOrderDto) {
        //1 添加商品订单 订单主表  订单明细表
        XcOrders xcOrders = saveXcOrders(userId, addOrderDto);

        //2 添加支付记录
        XcPayRecord payRecord = createPayRecord(xcOrders);

        //3 生成二维码
        String qrCode = "null";
        try {
            //url要可以被模拟器访问到，url为下单接口(稍后定义)
            String url = String.format(qrcodeurl, payRecord.getPayNo());
            qrCode = new QRCodeUtil().createQRCode(url, 200, 200);
        } catch (IOException e) {
            XueChengPlusException.cast("生成二维码出错");
        }
        PayRecordDto payRecordDto = new PayRecordDto();
        BeanUtils.copyProperties(payRecord,payRecordDto);
        payRecordDto.setQrcode(qrCode);
        
        return payRecordDto;
    }



    public XcOrders saveXcOrders(String userId,AddOrderDto addOrderDto){
        //进行幂等性判断 同一个选课记录只能有一个订单
        XcOrders order = getOrderByBusinessId(addOrderDto.getOutBusinessId());
        if(order!=null){
            return order;
        }
        order = new XcOrders();
        //1 添加商品订单 订单主表  订单明细表
        //生成订单号
        long orderId = IdWorkerUtils.getInstance().nextId();
        order.setId(orderId);
        order.setTotalPrice(addOrderDto.getTotalPrice());
        order.setCreateDate(LocalDateTime.now());
        order.setStatus("600001");//未支付
        order.setUserId(userId);
        order.setOrderType(addOrderDto.getOrderType());
        order.setOrderName(addOrderDto.getOrderName());
        order.setOrderDetail(addOrderDto.getOrderDetail());
        order.setOrderDescrip(addOrderDto.getOrderDescrip());
        order.setOutBusinessId(addOrderDto.getOutBusinessId());//选课记录id
        int insert = ordersMapper.insert(order);
        if (insert<=0){
            XueChengPlusException.cast("添加订单失败");
        }
        //插入订单明细表
        String orderDetailJson = addOrderDto.getOrderDetail();
        List<XcOrdersGoods> xcOrdersGoodsList = JSON.parseArray(orderDetailJson, XcOrdersGoods.class);
        xcOrdersGoodsList.forEach(goods->{
            XcOrdersGoods xcOrdersGoods = new XcOrdersGoods();
            BeanUtils.copyProperties(goods,xcOrdersGoods);
            xcOrdersGoods.setOrderId(orderId);//订单号
            ordersGoodsMapper.insert(xcOrdersGoods);
        });
        return order;
    }

    //根据业务id查询订单 业务id就是选课记录表id
    public XcOrders getOrderByBusinessId(String businessId) {
        XcOrders orders = ordersMapper.selectOne(new LambdaQueryWrapper<XcOrders>().eq(XcOrders::getOutBusinessId, businessId));
        return orders;
    }


    //保存你支付记录方法
    public XcPayRecord createPayRecord(XcOrders orders){
        if(orders==null){
            XueChengPlusException.cast("订单不存在");
        }
        if(orders.getStatus().equals("600002")){
            XueChengPlusException.cast("订单已支付");
        }
        //不存在再添加支付记录
        XcPayRecord payRecord = new XcPayRecord();

        payRecord.setPayNo(IdWorkerUtils.getInstance().nextId());//支付记录号  传给支付宝
        payRecord.setOrderId(orders.getId());//商品订单号
        payRecord.setOrderName(orders.getOrderName());
        payRecord.setTotalPrice(orders.getTotalPrice());
        payRecord.setCurrency("CNY");
        payRecord.setCreateDate(LocalDateTime.now());
        payRecord.setStatus("601001");//未支付
        payRecord.setUserId(orders.getUserId());
        int insert = payRecordMapper.insert(payRecord);
        if (insert<=0){
            XueChengPlusException.cast("插入订单失败");
        }
        return payRecord;

    }



    @Override
    public XcPayRecord getPayRecordByPayno(String payNo) {
        XcPayRecord xcPayRecord = payRecordMapper.selectOne(new LambdaQueryWrapper<XcPayRecord>().eq(XcPayRecord::getPayNo, payNo));
        return xcPayRecord;
    }



    //查询支付结果接口 若成功更新状态
    @Override
    public PayRecordDto queryPayResult(String payNo){
//        XcPayRecord payRecord = getPayRecordByPayno(payNo);
//        if (payRecord == null) {
//            XueChengPlusException.cast("请重新点击支付获取二维码");
//        }
//        //支付状态
//        String status = payRecord.getStatus();
//        //如果支付成功直接返回
//        if ("601002".equals(status)) {
//            PayRecordDto payRecordDto = new PayRecordDto();
//            BeanUtils.copyProperties(payRecord, payRecordDto);
//            return payRecordDto;
//        }
        //1 从支付宝查询支付结果
        PayStatusDto payStatusDto = queryPayResultFromAlipay(payNo);

        //2 更新保存支付结果
        currentProxy.saveAliPayStatus(payStatusDto);
        //重新查询支付记录
        XcPayRecord payRecord = getPayRecordByPayno(payNo);
        PayRecordDto payRecordDto = new PayRecordDto();
        BeanUtils.copyProperties(payRecord, payRecordDto);
        return payRecordDto;

    }

    /**
     * 请求支付宝查询支付结果
     * @param payNo 支付交易号
     * @return 支付结果
     */
    public PayStatusDto queryPayResultFromAlipay(String payNo){
        AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.URL, APP_ID, APP_PRIVATE_KEY, AlipayConfig.FORMAT, AlipayConfig.CHARSET, ALIPAY_PUBLIC_KEY,AlipayConfig.SIGNTYPE);
        AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
        JSONObject bizContent = new JSONObject();
        bizContent.put("out_trade_no", payNo);
        //bizContent.put("trade_no", "2014112611001004680073956707");
        request.setBizContent(bizContent.toString());
        AlipayTradeQueryResponse response = null; //通过alipayClient调用API，获得对应的response类
        try {
            response = alipayClient.execute ( request );
            if (!response.isSuccess()){//交易不成功
                XueChengPlusException.cast("请求支付宝查询支付结果失败");
            }
        } catch (AlipayApiException e) {
            e.printStackTrace();
            XueChengPlusException.cast("请求支付宝查询支付结果异常");
        }
        //解析支付结果
        String body = response.getBody();
        Map bodyMap = JSON.parseObject(body, Map.class);
        Map<String,String> alipayTradeQueryResponse = (Map<String,String>) bodyMap.get("alipay_trade_query_response");

        PayStatusDto payStatusDto = new PayStatusDto();
        payStatusDto.setOut_trade_no(payNo);
        payStatusDto.setTrade_no(alipayTradeQueryResponse.get("trade_no"));//支付宝交易号
        payStatusDto.setTrade_status(alipayTradeQueryResponse.get("trade_status"));
        payStatusDto.setApp_id(APP_ID);
        payStatusDto.setTotal_amount(alipayTradeQueryResponse.get("total_amount"));

        return payStatusDto;
    }


    /**
     * @description 保存支付宝支付结果
     * @param payStatusDto  支付结果信息
     */
    @Transactional
    public void saveAliPayStatus(PayStatusDto payStatusDto) {
        //前置校验
        String payNo = payStatusDto.getOut_trade_no();
        XcPayRecord payRecordByPayno = getPayRecordByPayno(payNo);
        if (payRecordByPayno==null){
            XueChengPlusException.cast("找不到支付记录");
        }
        Long orderId = payRecordByPayno.getOrderId();
        XcOrders xcOrders = ordersMapper.selectById(orderId);
        if (xcOrders==null){
            XueChengPlusException.cast("找不到相关订单");
        }
        //支付状态  已经是成功不处理
        String status = payRecordByPayno.getStatus();
        if ("601002".equals(status)) {
            return;
        }
        //如果支付成功
        String tradeStatus = payStatusDto.getTrade_status();
        if (tradeStatus.equals("TRADE_SUCCESS")){
            //支付状态为成功
            payRecordByPayno.setStatus("601002");
            payRecordByPayno.setOutPayChannel("Alipay");
            payRecordByPayno.setOutPayNo(payStatusDto.getTrade_no());//支付宝交易号
            payRecordByPayno.setPaySuccessTime(LocalDateTime.now());//通知时间
            payRecordMapper.updateById(payRecordByPayno);

            //订单状态为成功
            xcOrders.setStatus("600002");
            ordersMapper.updateById(xcOrders);


            //调用消息队列发送消息
            MqMessage mqMessage = mqMessageService.addMessage("payresult_notify", xcOrders.getOutBusinessId(), xcOrders.getOrderType(), null);
            //发送消息
            notifyPayResult(mqMessage);
        }
    }

    @Override
    public void notifyPayResult(MqMessage message) {
        //消息内容
        String jsonString = JSON.toJSONString(message);
        //创建持久化消息
        Message messageObj = MessageBuilder.withBody(jsonString.getBytes(StandardCharsets.UTF_8)).setDeliveryMode(MessageDeliveryMode.PERSISTENT).build();

        Long id = message.getId();
        //全局消息id
        CorrelationData correlationData = new CorrelationData(id.toString());
        //使用CD指定回调方法
        correlationData.getFuture().addCallback(result->{
            if (result.isAck()){
                //消息发送到了交换机 成功了
                log.debug("发送消息到交换机成功{}",jsonString);
                //将数据库消息表删掉
                mqMessageService.completed(id);
            }else{
                log.debug("发送消息到交换机失败{}",jsonString);
                XueChengPlusException.cast("发送消息到交换机失败");
            }

        },ex->{
            log.debug("发送消息到交换机失败{}",jsonString);
            XueChengPlusException.cast("发送消息到交换机失败");
        });
        rabbitTemplate.convertAndSend(PayNotifyConfig.PAYNOTIFY_EXCHANGE_FANOUT,"",messageObj,correlationData);



    }
}